/***************************************************************
 * The author disclaims copyright to this source code.
 * In place of a legal notice, here is a blessing:
 *
 *    May you do good and not evil.
 *    May you find forgiveness for yourself and forgive others.
 *    May you share freely, never taking more than you give.
 *
 * Any feedback will be appreciated. mailto:k-tak@void.in
 ***************************************************************/
%module libsenna
%include typemaps.i
%include exception.i
%include cstring.i
%include carrays.i
%{
#include <senna/senna.h>
%}


/**************************************************************************
 *  Typedefs
 **************************************************************************/
typedef unsigned int sen_id;


/**************************************************************************
 *  Typemaps
 **************************************************************************/
%typemap(in) char *keyoutput (char tmpkey[SEN_SYM_MAX_KEY_SIZE+1]) {
   $1 = tmpkey;
}
%cstring_bounded_output(char *keyoutput, SEN_SYM_MAX_KEY_SIZE);

%typemap(in) char *pathoutput (char tmppath[SEN_PATH_MAX_LENGTH+1]) {
   $1 = tmppath;
}
%cstring_bounded_output(char *pathoutput, SEN_PATH_MAX_LENGTH);

%apply (const char *STRING, size_t LENGTH) { (const char *input_str1, unsigned int input_len1) };
%apply (const char *STRING, size_t LENGTH) { (const char *input_str2, unsigned int input_len2) };
%apply (const char *STRING, size_t LENGTH) { (const char *input_str3, unsigned int input_len3) };


/**************************************************************************
 *  Constants
 **************************************************************************/
#define SEN_INDEX_NORMALIZE                     0x0001
#define SEN_INDEX_SPLIT_ALPHA                   0x0002
#define SEN_INDEX_SPLIT_DIGIT                   0x0004
#define SEN_INDEX_SPLIT_SYMBOL                  0x0008
#define SEN_INDEX_MORPH_ANALYSE                 0x0000
#define SEN_INDEX_NGRAM                         0x0010
#define SEN_INDEX_DELIMITED                     0x0020
#define SEN_INDEX_ENABLE_SUFFIX_SEARCH          0x0100
#define SEN_INDEX_DISABLE_SUFFIX_SEARCH         0x0200
#define SEN_INDEX_WITH_STORE                    0x1000
#define SEN_INDEX_WITH_VACUUM                   0x8000
#define SEN_SYM_WITH_SIS                        0x80000000
#define SEN_SYM_NIL				0
#define SEN_SNIP_NORMALIZE                      0x0001

/* Pyrost specific constants */
#define SEN_SNIP_MAPPING_NONE			0
#define SEN_SNIP_MAPPING_ESCAPE_HTML_SPECIALS	(-1)
%{
#define SEN_PATH_MAX_LENGTH			1024
%}
#define SEN_PATH_MAX_LENGTH			1024

typedef enum {
   sen_success = 0,
   sen_memory_exhausted,
   sen_invalid_format,
   sen_file_operation_error,
   sen_invalid_argument,
   sen_other_error
} sen_rc;

typedef enum {
   sen_enc_default = 0,
   sen_enc_none,
   sen_enc_euc_jp,
   sen_enc_utf8,
   sen_enc_sjis,
   sen_enc_latin1,
   sen_enc_koi8r
} sen_encoding;

typedef enum {
   sen_rec_document = 0,
   sen_rec_section,
   sen_rec_position,
   sen_rec_userdef,
   sen_rec_none
} sen_rec_unit;

typedef enum {
   sen_sel_or = 0,
   sen_sel_and,
   sen_sel_but,
   sen_sel_adjust
} sen_sel_operator;

typedef enum {
   sen_sel_exact = 0,
   sen_sel_partial,
   sen_sel_unsplit,
   sen_sel_near,
   sen_sel_similar,
   sen_sel_term_extract
} sen_sel_mode;

typedef enum {
   sen_sort_descending = 0,
   sen_sort_ascending
} sen_sort_mode;

typedef enum {
   sen_log_none = 0,
   sen_log_emerg,
   sen_log_alert,
   sen_log_crit,
   sen_log_error,
   sen_log_warning,
   sen_log_notice,
   sen_log_info,
   sen_log_debug,
   sen_log_dump
} sen_log_level;


/**************************************************************************
 *  Basic APIs
 **************************************************************************/
sen_rc sen_init(void);
sen_rc sen_fin(void);

%rename(sen_index_create) my_index_create;
%inline {
   static sen_index *my_index_create(const char* path,
				     int flags,
				     int initial_n_segments,
				     sen_encoding encoding)
   {
      return sen_index_create(path, 0, flags, initial_n_segments, encoding);
   }
}

sen_index *sen_index_open(const char *path);
sen_rc sen_index_close(sen_index *i);
sen_rc sen_index_remove(const char *path);
sen_rc sen_index_rename(const char *old_name, const char *new_name);


%rename(sen_index_upd) my_index_upd;
%inline {
   static sen_rc my_index_upd(sen_index *i, const char *key,
			      const char *input_str1, unsigned int input_len1,
			      const char *input_str2, unsigned int input_len2)
   {
      return sen_index_upd(i, key,
			   input_str1, input_len1,
			   input_str2, input_len2);
   }
}

sen_records *sen_index_sel(sen_index *i,
			   const char *input_str1, unsigned input_len1);

%rename(sen_records_next) my_records_next;
%inline {
   static int my_records_next(sen_records *r)
   {
      int ret = 0;
      
      ret = sen_records_next(r, NULL, 0, NULL);
      return (ret != 0);
   }
}

sen_rc sen_records_rewind(sen_records *r);
int sen_records_curr_score(sen_records *r);

%rename(sen_records_curr_key) my_records_curr_key;
%inline {
   static void my_records_curr_key(sen_records *r, char* keyoutput)
   {
      int ret = 0;
      
      ret = sen_records_curr_key(r, keyoutput, SEN_SYM_MAX_KEY_SIZE);
      keyoutput[ret] = 0;
   }
}

int sen_records_nhits(sen_records *r);

%rename(sen_records_find) my_records_find;
%inline {
   static int my_records_find(sen_records *r, const char *key)
   {
      return sen_records_find(r, key);
   }
}

sen_rc sen_records_close(sen_records *r);



/**************************************************************************
 *  Advanced APIs
 **************************************************************************/
sen_values *sen_values_open(void);
sen_rc sen_values_close(sen_values *v);
sen_rc sen_values_add(sen_values *v,
		      const char *input_str1, unsigned int input_len1,
		      unsigned int weight);

sen_records *sen_records_open(sen_rec_unit record_unit, 
                              sen_rec_unit subrec_unit,
                              unsigned int max_n_subrecs);
sen_records *sen_records_union(sen_records *a, sen_records *b);
sen_records *sen_records_subtract(sen_records *a, sen_records *b);
sen_records *sen_records_intersect(sen_records *a, sen_records *b);
int sen_records_difference(sen_records *a, sen_records *b);

%rename(sen_records_sort) my_records_sort;
%inline {
   static sen_rc my_records_sort(sen_records *records,
				 int limit,
				 sen_sort_mode mode)
   {
      sen_sort_optarg opts;
      
      opts.mode = mode;
      opts.compar = NULL;
      opts.compar_arg = NULL;
      
      return sen_records_sort(records, limit, &opts);
   }
}

%rename(sen_records_group) my_records_group;
%inline {
   static sen_rc my_records_group(sen_records *r,
				  int limit,
				  sen_sort_mode mode)
   {
      sen_group_optarg opts;

      opts.mode = mode;
      opts.func = NULL;
      opts.func_arg = NULL;
      opts.key_size = 0;

      return sen_records_group(r, limit, &opts);
   }
}

const sen_recordh * sen_records_curr_rec(sen_records *r);


%rename(sen_records_at) my_records_at;
%newobject my_records_at;
%inline {
   typedef struct _swig_sen_record_at_info {
         const sen_recordh *rh;
         int score;
         int n_subrecs;
   } swig_sen_record_at_info;

   static swig_sen_record_at_info *my_records_at(
      sen_records *r, const char *key,
      unsigned section, unsigned pos)
   {
      int score = 0;
      int n_subrecs = 0;
      
      const sen_recordh *ret = sen_records_at(r, key, section, pos,
					      &score, &n_subrecs);
      if (ret) {
	 swig_sen_record_at_info* info =
	    (swig_sen_record_at_info*)malloc(sizeof(swig_sen_record_at_info));
	 if (info) {
	    info->rh = ret;
	    info->score = score;
	    info->n_subrecs = n_subrecs;
	 }
	 return info;
      } else {
	 return NULL;
      }
   }
}


%rename(sen_record_info) my_record_info;
%newobject my_record_info;
%inline {
   typedef struct _swig_sen_record_subrec_info {
         char key[SEN_SYM_MAX_KEY_SIZE+1];
         int section;
         int pos;
         int score;
         int n_subrecs;
   } swig_sen_record_subrec_info;

   typedef struct _swig_sen_record_info {
         swig_sen_record_subrec_info rec;
         int n_subrecs;
   } swig_sen_record_info;

   static swig_sen_record_info *my_record_info(
      sen_records *r, const sen_recordh *rh)
   {
      sen_rc rc;
      int keysize;
      swig_sen_record_info* ret =
	 (swig_sen_record_info *)malloc(sizeof(swig_sen_record_info));
      if (!ret) {
	 return NULL;
      }
      memset(ret, 0, sizeof(swig_sen_record_info));

      rc = sen_record_info(r, rh,
			   ret->rec.key, SEN_SYM_MAX_KEY_SIZE, &keysize,
			   &(ret->rec.section), &(ret->rec.pos),
			   &(ret->rec.score), &(ret->n_subrecs));
      if (rc == sen_success) {
	 ret->rec.key[SEN_SYM_MAX_KEY_SIZE] = 0;
	 return ret;
      } else {
	 free(ret);
	 return NULL;
      }
   }
}


%rename(sen_record_subrec_info) my_record_subrec_info;
%newobject my_record_subrec_info;
%inline {
   static swig_sen_record_subrec_info *my_record_subrec_info(
      sen_records *r, const sen_recordh *rh, int index)
   {
      sen_rc rc;
      int keysize;
      swig_sen_record_subrec_info *ret =
	 (swig_sen_record_subrec_info *)malloc(
	    sizeof(swig_sen_record_subrec_info));
      if (!ret) {
	 return NULL;
      }
      memset(ret, 0, sizeof(swig_sen_record_subrec_info));

      rc = sen_record_subrec_info(r, rh, index,
				  ret->key, SEN_SYM_MAX_KEY_SIZE, &keysize,
				  &(ret->section), &(ret->pos), &(ret->score));
      if (rc == sen_success) {
	 ret->key[SEN_SYM_MAX_KEY_SIZE] = 0;
	 return ret;
      } else {
	 free(ret);
	 return NULL;
      }
   }
}


sen_index *sen_index_create_with_keys(const char *path, sen_sym *keys,
				      int flags,
                                      int initial_n_segments,
				      sen_encoding encoding);
sen_index *sen_index_open_with_keys(const char *path, sen_sym *keys);
sen_rc sen_index_update(sen_index *i, const void *key, unsigned int section,
                        sen_values *oldvalues, sen_values *newvalues);


%array_class(int, WeightVector);
%rename(sen_index_select) my_index_select;
%inline {
   static sen_rc my_index_select(sen_index *i,
				 const char *input_str1,
				 unsigned int input_len1,
				 sen_records *r,
				 sen_sel_operator op, sen_sel_mode mode,
				 int similarity_threshold, int max_interval,
				 int *weight_vector, int vector_size)
   {
      sen_select_optarg opt;

      memset(&opt, 0, sizeof(opt));
      opt.mode = mode;
      opt.similarity_threshold = similarity_threshold;
      opt.max_interval = max_interval;
      opt.weight_vector = weight_vector;
      opt.vector_size = vector_size;
      
      return sen_index_select(i, input_str1, input_len1, r, op, &opt);
   }
}


%rename(sen_index_info) my_index_info;
%newobject my_index_info;
%inline {
   typedef struct _swig_sen_index_info {
         int key_size;
         int flags;
         int initial_n_segments;
         sen_encoding encoding;
         unsigned int nrecords_keys;
         unsigned int file_size_keys;
         unsigned int nrecords_lexicon;
         unsigned int file_size_lexicon;
         unsigned int inv_seg_size;
         unsigned int inv_chunk_size;
   } swig_sen_index_info;

   static swig_sen_index_info *my_index_info(sen_index *i)
   {
      sen_rc rc;
      swig_sen_index_info *ret =
	 (swig_sen_index_info *)malloc(sizeof(swig_sen_index_info));
      if (!ret) {
	 return NULL;
      }
      memset(ret, 0, sizeof(swig_sen_index_info));

      rc = sen_index_info(i, &(ret->key_size), &(ret->flags),
			  &(ret->initial_n_segments), &(ret->encoding),
			  &(ret->nrecords_keys), &(ret->file_size_keys),
			  &(ret->nrecords_lexicon), &(ret->file_size_lexicon),
			  &(ret->inv_seg_size), &(ret->inv_chunk_size));
      if (rc != sen_success) {
	 free(ret);
	 return NULL;
      }

      return ret;
   }
}


%rename(sen_index_path) my_index_path;
%inline {
   static void my_index_path(sen_index *i, char *pathoutput)
   {
      int ret = 0;
      
      ret = sen_index_path(i, pathoutput, SEN_PATH_MAX_LENGTH);
      pathoutput[ret] = 0;
   }
}


sen_query *sen_query_open(const char *input_str1, unsigned int input_len1,
			  sen_sel_operator default_op,
                          int max_exprs, sen_encoding encoding);

%cstring_output_allocate_size(char **rest_query, unsigned int *rest_len,);
%rename(sen_query_rest) my_query_rest;
%inline {
   static void my_query_rest(sen_query *q,
			     char **rest_query, unsigned int *rest_len)
   {
      *rest_len = sen_query_rest(q, (const char** const)rest_query);
   }
}


sen_rc sen_query_close(sen_query *q);
sen_rc sen_query_exec(sen_index *i, sen_query *q, sen_records *r,
		      sen_sel_operator op);

sen_rc sen_index_del(sen_index *i, const void *key);


/**************************************************************************
 *  Low-level APIs
 **************************************************************************/
sen_rc sen_set_close(sen_set *set);
sen_set_cursor *sen_set_cursor_open(sen_set *set);

%rename(sen_set_sym_id_cursor_next) my_set_cursor_next;
%apply sen_id *OUTPUT { sen_id *idoutput };
%inline {
   static sen_set_eh *my_set_cursor_next(sen_set_cursor *cursor,
					 sen_id *idoutput)
   {
      sen_id *id = NULL;
      sen_set_eh *ret = NULL;

      ret = sen_set_cursor_next(cursor, (void**)&id, NULL);
      if (ret && id) {
	 *idoutput = *id;
      } else {
	 ret = NULL;
	 *idoutput = SEN_SYM_NIL;
      }
      return ret;
   }
}

sen_rc sen_set_cursor_close(sen_set_cursor *cursor);

%rename(sen_sym_create) my_sym_create;
%inline {
   sen_sym *my_sym_create(const char *path,
			  unsigned int flags, sen_encoding encoding)
   {
      return sen_sym_create(path, 0, flags, encoding);
   }
}

sen_sym * sen_sym_open(const char *path);


%rename(sen_sym_info) my_sym_info;
%newobject my_sym_info;
%inline {
   typedef struct _swig_sen_sym_info {
         int key_size;
         unsigned int flags;
         sen_encoding encoding;
         unsigned int nrecords;
         unsigned int file_size;
   } swig_sen_sym_info;

   static swig_sen_sym_info *my_sym_info(sen_sym *sym)
   {
      sen_rc rc;
      swig_sen_sym_info *ret = NULL;

      ret = (swig_sen_sym_info *)malloc(sizeof(swig_sen_sym_info));
      if (!ret) {
	 return NULL;
      }
      memset(ret, 0, sizeof(swig_sen_sym_info));

      rc = sen_sym_info(sym, &(ret->key_size), &(ret->flags),
			&(ret->encoding), &(ret->nrecords),
			&(ret->file_size));
      if (rc != sen_success) {
	 free(ret);
	 return NULL;
      }
      return ret;
   }
}

sen_rc sen_sym_close(sen_sym *sym);
sen_rc sen_sym_remove(const char *path);
sen_id sen_sym_get(sen_sym *sym, const char *key);
sen_id sen_sym_at(sen_sym *sym, const char *key);
sen_rc sen_sym_del(sen_sym *sym, const char *key);
unsigned int sen_sym_size(sen_sym *sym);

%rename(sen_sym_key) my_sym_key;
%inline {
   static void my_sym_key(sen_sym *sym, sen_id id, char *keyoutput)
   {
      sen_sym_key(sym, id,
		  (unsigned char*)keyoutput,
		  SEN_SYM_MAX_KEY_SIZE);
   }
}

sen_set * sen_sym_prefix_search(sen_sym *sym, const char *key);
sen_set * sen_sym_suffix_search(sen_sym *sym, const char *key);
sen_id sen_sym_common_prefix_search(sen_sym *sym, const char *key);
int sen_sym_pocket_get(sen_sym *sym, sen_id id);
sen_rc sen_sym_pocket_set(sen_sym *sym, sen_id id, unsigned int value);
sen_id sen_sym_next(sen_sym *sym, sen_id id);


%{
   typedef struct _swig_sen_snip_info {
	 char *keyword;
	 unsigned int keyword_len;
	 char *opentag;
	 unsigned int opentag_len;
	 char *closetag;
	 unsigned int closetag_len;
   } swig_sen_snip_info;
   
   typedef struct _swig_sen_snip {
	 swig_sen_snip_info *info;
	 unsigned int num_info;
	 unsigned int max_tagged_len;
	 char *result;
	 sen_snip *snip;
   } swig_sen_snip;
   
   static void my_free_swig_sen_snip_info(swig_sen_snip_info *info)
   {
      if (!info) {
	 return;
      }

      if (info->keyword) {
	 free(info->keyword);
      }
      if (info->opentag) {
	 free(info->opentag);
      }
      if (info->closetag) {
	 free(info->closetag);
      }
   }
   
   static sen_rc my_free_swig_sen_snip(swig_sen_snip *snip)
   {
      sen_rc rc = sen_success;

      if (!snip) {
	 return sen_invalid_argument;
      }
      
      if (snip->info) {
	 unsigned int i;
	 for (i=0; i<snip->num_info; ++i) {
	    my_free_swig_sen_snip_info(snip->info + i);
	 }
	 free(snip->info);
      }
      if (snip->result) {
	 free(snip->result);
      }
      if (snip->snip) {
	 rc = sen_snip_close(snip->snip);
      }
      free(snip);

      return rc;
   }
   
   static sen_rc my_add_swig_sen_snip_info(
      swig_sen_snip *snip,
      const char *keyword, unsigned int keyword_len,
      const char *opentag, unsigned int opentag_len,
      const char *closetag, unsigned int closetag_len)
   {
      swig_sen_snip_info *info = NULL;
      
      if (!snip || !keyword) {
	 return sen_invalid_argument;
      }
      if (snip->info) {
	 snip->info = (swig_sen_snip_info *)realloc(
	    snip->info,
	    sizeof(swig_sen_snip_info) * snip->num_info+1);
      } else {
	 snip->info = (swig_sen_snip_info *)malloc(
	    sizeof(swig_sen_snip_info));
      }
      if (snip->info == NULL) {
	 return sen_memory_exhausted;
      } else {
	 memset(snip->info + snip->num_info, 0, sizeof(swig_sen_snip_info));
	 snip->num_info += 1;
      }
      
      info = snip->info + snip->num_info - 1;
      do {
	 info->keyword = malloc((size_t)keyword_len);
	 if (!(info->keyword)) break;
	 memcpy(info->keyword, keyword, (size_t)keyword_len);
	 info->keyword_len = keyword_len;

	 if (opentag) {
	    info->opentag = malloc((size_t)opentag_len);
	    if (!(info->opentag)) break;
	    memcpy(info->opentag, opentag, (size_t)opentag_len);
	    info->opentag_len = opentag_len;
	 }

	 if (closetag) {
	    info->closetag = malloc((size_t)closetag_len);
	    if (!(info->closetag)) break;
	    memcpy(info->closetag, closetag, (size_t)closetag_len);
	    info->closetag_len = closetag_len;
	 }
      } while (0);

      if (info->keyword==NULL ||
	  (opentag && info->opentag==NULL) ||
	  (closetag && info->closetag==NULL)) {
	 return sen_memory_exhausted;
      }
      
      return sen_success;
   }
%}


%rename(sen_snip_open) my_snip_open;
%inline {
   static swig_sen_snip *my_snip_open(
      sen_encoding encoding, int flags,
      unsigned int width,
      unsigned int max_results,
      const char *input_str1, unsigned int input_len1,
      const char *input_str2, unsigned int input_len2,
      int mapping)
   {
      sen_rc rc;
      swig_sen_snip *ret = NULL;
      ret = (swig_sen_snip *)malloc(sizeof(swig_sen_snip));
      if (!ret) {
	 return NULL;
      }
      memset(ret, 0, sizeof(swig_sen_snip));
      
      rc = my_add_swig_sen_snip_info(ret,
				     "", 0,
				     input_str1, input_len1,
				     input_str2, input_len2);
      if (rc != sen_success) {
	 /*
         puts("cannot add snipinfo");
	 */
	 my_free_swig_sen_snip(ret);
	 return NULL;
      }
      
      ret->snip = sen_snip_open(encoding, flags, width, max_results,
				ret->info[0].opentag,
				ret->info[0].opentag_len,
				ret->info[0].closetag,
				ret->info[0].closetag_len,
				(sen_snip_mapping*)mapping);
      if (ret->snip == NULL) {
	 /*
         printf("%d, %d, %d, %d, %s, %s, %d\n",
		encoding, flags, width, max_results,
		defaultopentag, defaultclosetag, mapping);
	 */
	 my_free_swig_sen_snip(ret);
	 return NULL;
      }
      
      return ret;
   }
}

%rename(sen_snip_close) my_free_swig_sen_snip;
sen_rc my_free_swig_sen_snip(swig_sen_snip *snip);

%rename(sen_snip_add_cond) my_snip_add_cond;
%inline {
   static sen_rc my_snip_add_cond(swig_sen_snip *snip,
				  const char *input_str1,
				  unsigned int input_len1,
				  const char *input_str2,
				  unsigned int input_len2,
				  const char *input_str3,
				  unsigned int input_len3)
   {
      sen_rc rc;
      
      if (!snip) {
	 return sen_invalid_argument;
      }
      
      rc = my_add_swig_sen_snip_info(snip,
				     input_str1, input_len1,
				     input_str2, input_len2,
				     input_str3, input_len3);
      if (rc != sen_success) {
	 return rc;
      }
      
      rc = sen_snip_add_cond(snip->snip,
			     snip->info[snip->num_info-1].keyword,
			     snip->info[snip->num_info-1].keyword_len,
			     snip->info[snip->num_info-1].opentag,
			     snip->info[snip->num_info-1].opentag_len,
			     snip->info[snip->num_info-1].closetag,
			     snip->info[snip->num_info-1].closetag_len);
      return rc;
   }
}

%rename(sen_snip_exec) my_snip_exec;
%apply unsigned int *OUTPUT { unsigned int *snip_nresults };
%inline {
   static sen_rc my_snip_exec(swig_sen_snip *snip,
			      const char *input_str1, unsigned int input_len1,
			      unsigned int *snip_nresults)
   {
      sen_rc rc;
      unsigned int max_tagged_len;

      *snip_nresults = 0;
      if (!snip) {
	 return sen_invalid_argument;
      }
      
      if (snip->result) {
	 free(snip->result);
	 snip->result = NULL;
	 snip->max_tagged_len = 0;
      }
      
      rc = sen_snip_exec(snip->snip, input_str1, input_len1, snip_nresults,
			 &max_tagged_len);
      if (rc != sen_success) {
	 return rc;
      }
      
      snip->max_tagged_len = max_tagged_len;
      snip->result = (char *)malloc(max_tagged_len + 1);
      if (snip->result == NULL) {
	 snip->max_tagged_len = 0;
	 return sen_memory_exhausted;
      }
      
      return rc;
   }
}

%cstring_output_allocate_size(char **snip_result, unsigned int *snip_result_len,);
%rename(sen_snip_get_result) my_snip_get_result;
%inline {
   static void my_snip_get_result(swig_sen_snip *snip,
				    unsigned int index,
				    char **snip_result,
				    unsigned int *snip_result_len)
   {
      sen_rc rc;
      
      if (!snip || !(snip->snip) || !(snip->result)) {
	 *snip_result = NULL;
	 *snip_result_len = 0;
	 return;
      }

      *snip_result = snip->result;
      *snip_result_len = snip->max_tagged_len;
      rc = sen_snip_get_result(snip->snip, index,
			       *snip_result, snip_result_len);
      if (rc != sen_success) {
	 *snip_result = NULL;
	 *snip_result_len = 0;
      }
   }
}
